﻿package de.gameduell.framework.gui.button {
	import de.gameduell.framework.gui.style.StyleDescriptor;
	import de.gameduell.framework.gui.style.StyleConfig;
	
	import de.gameduell.framework.gui.util.ToolTip;
	import de.gameduell.framework.locale.Locale;
	import de.gameduell.framework.locale.LocalizableSprite;
	import de.gameduell.framework.util.Audio;
	
	import de.gameduell.framework.debug.Debug;

	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextFieldAutoSize;

	/**
	 * IMPORTANT:
	 * the name of the button and the name of 
	 * the label has to be the same 
	 */

	public class Button extends LocalizableSprite {
		
		//states
		public static const DISABLED:String  = "disabled";
		public static const UP:String 		 = "up";
		public static const DOWN:String 	 = "down";
		public static const OVER:String 	 = "over";
		public static const OUT:String 	 	 = "out";
		public static const CLICK:String	 = "ButtonClick";
		public static const INACTIVE_CLICK:String = "inactive_click";
		
		//autosize
		public static const LEFT:String   = TextFieldAutoSize.LEFT;
		public static const RIGHT:String  = TextFieldAutoSize.RIGHT;
		public static const CENTER:String = TextFieldAutoSize.CENTER;
		public static const NONE:String   = TextFieldAutoSize.NONE;
		
		
		protected static const DEFAULT_AUTOSIZE:String = NONE;
		
		
		private var _offset:int;
		private var _text:String;
		protected var _active:Boolean;
		private var states:Array;
		
		protected var _toolTip:ToolTip;	
		protected var locale:Locale;	
		protected var upState:ButtonState;
		protected var downState:ButtonState;
		protected var overState:ButtonState;
		protected var disabledState:ButtonState;
		protected var currState:ButtonState;
		protected var audio:Audio;		
		protected var sounds:Array;
		protected var _resizeHitterEnabled:Boolean;
	
		private const TYPE:String = "button";	
			
		/**
		 * constructor 
		 * @param aClip:Sprite the Sprite the Button is created from
		 * @param aId:String   optional String to identify the corresponding xml tag in the language xml
		 */
		public function Button(aClip:Sprite,aId:String = null, aResizeHitterEnabled:Boolean = true, applyStyle:Boolean = false, customStyleId:String = null){	
			super(aClip);	
			audio  = Audio.getInstance();
			sounds = new Array();
			type   = TYPE;
			_resizeHitterEnabled = aResizeHitterEnabled;
			
			mouseChildren = false;
			buttonMode	  = true;
			_active		  = true;
			
			_text         = "";
			_toolTip 	  = null;
		
			_id = aId != null ? aId : sprite.name;
			
			// build style from config? read by localeId
			if (applyStyle) {
				var styleId:String = (customStyleId != null) ? customStyleId : _id;
				var desc:StyleDescriptor = StyleConfig.getInstance().getStyleDescriptor(styleId);
				//Debug.trace("button " + aId + " use style=" + styleId + " found=" + (desc != null));
				desc.build(aClip);
			}
			
			upState   	  = createState(UP);
			downState 	  = createState(DOWN);
			overState 	  = createState(OVER);
			disabledState = createState(DISABLED);
					
			states = new Array(upState,downState,overState,disabledState);

			currState = upState;
			addChild(upState.sprite);
			
			createHitter();
			
			locale = Locale.getInstance();
			locale.localize(this);
						
			addEventListener(MouseEvent.MOUSE_OUT, mouseEvent);
			addEventListener(MouseEvent.MOUSE_OVER, mouseEvent);
			addEventListener(MouseEvent.MOUSE_UP, mouseEvent);
			addEventListener(MouseEvent.MOUSE_DOWN, mouseEvent);
		}
		
		private function createHitter():void{
			var hitterSprite:Sprite = getChildByName("hitter") as Sprite;
			
			if(hitterSprite != null){
				hitArea = hitterSprite;
			}else{
				hitArea = createDefaultHitter();
			}
		}
		
		private function createDefaultHitter():Sprite{
			var hitterSprite:Sprite = new Sprite();
			var hitterShape:Shape = new Shape();
			hitterShape.graphics.beginFill(0xffffff, 0);
			hitterShape.graphics.drawRect(0, 0, upState.width, upState.height);
			hitterShape.graphics.endFill();
			hitterSprite.addChild(hitterShape);
			sprite.addChild(hitterSprite);
			return hitterSprite;
		}
		
		/*###################################################
		#		   			  SETTER						#
		#####################################################*/
		
		/**
		 * @param aText:String 	 the text that the Button will show
		 * @param isHtml:Boolean   sets if the Buttontext is shown as HTML text
		 * @param aAutoSize:String sets if and how the Buttonbackground resizes and aligns itself
		 */
		override public function setText(aText:String, isHtml:Boolean, aAutoSize:String):void {
			for(var i:* in states){
				var state:ButtonState = states[i];
				state.setText(aText, isHtml, aAutoSize);
			}
			_text = aText;
		}
		
		/**
		 * @param useToolTip:Boolean   sets if the Tooltip for this Button is activated
		 */
		public function set toolTip(useToolTip:Boolean):void{
			if(useToolTip && _toolTip == null){
				_toolTip = new ToolTip("tooltip",id+".alt",sprite,false);
				addLocalizable(_toolTip);		
			}
		}
		
		/**
		 * @param aId:String   sets manually the id to identify the according XML tag in the language xml
		 */
		override public function set id(aId:String):void{
			_id = aId;
			for(var i:int = 0;i< states.length;i++){
				var state:ButtonState = states[i];
				state.id = _id;
			}
			locale.localize(this);
		}	
		
		override public function get id():String{
			return _id;
		}
		
		public function set offset(aOffset:int):void{
			_offset = aOffset;
			for(var i:* in states){
				states[i].offset = _offset;
			}
		}
			
		/**
		 * actives or deactivates the button
		 */
		public function set active(isActive:Boolean):void{
			mouseEnabled = isActive;
			_active = isActive;
			
			if(isActive){
				removeEventListener(MouseEvent.MOUSE_UP, inactiveMouseEvent);
				addEventListener(MouseEvent.MOUSE_OUT, mouseEvent);
				addEventListener(MouseEvent.MOUSE_OVER, mouseEvent);
				addEventListener(MouseEvent.MOUSE_UP, mouseEvent);
				addEventListener(MouseEvent.MOUSE_DOWN, mouseEvent);
				setState(upState);
			}else{		
				addEventListener(MouseEvent.MOUSE_UP, inactiveMouseEvent);
				removeEventListener(MouseEvent.MOUSE_OUT, mouseEvent);
				removeEventListener(MouseEvent.MOUSE_OVER, mouseEvent);
				removeEventListener(MouseEvent.MOUSE_UP, mouseEvent);
				removeEventListener(MouseEvent.MOUSE_DOWN, mouseEvent);
				setState(disabledState);
			}	
		}
		
		/**
		 * makes it possible to get events even from deactivated Buttons
		 */
		public function enableInactiveClick():void{
			if(!_active){
				mouseEnabled = true;
			}
		}
		
		/**
		 * sets a sound for a specific mouseEvent
		 * 
		 * @param mouseEvent the trigger event
		 * @param soundId	 the triggered sound
		 */
		public function setSound(mouseEvent:String,soundId:String):void{
			sounds[mouseEvent] = soundId;
		}
		
		
		/*###################################################
		#		   			  GETTER						#
		#####################################################*/
		
		public function get active():Boolean{
			return _active;
		}
		
		public function get offset():int{
			return _offset;
		}
			
		public function get text():String{
			return _text;
		}
		
		public function get state():ButtonState{
			return currState;
		}
		
		public function getStates():Array{
			return states;
		}
			
		public function getToolTip():ToolTip{
			return _toolTip;
		}
		
		/*###################################################
		#		   			  PUBLIC						#
		#####################################################*/
		
		/**
		 * activates the button
		 */
		public function activate(e:Event = null):void{
			active = true;	
		}
		
		/**
		 * deactivates the button
		 */
		public function deactivate(e:Event = null):void{
			active = false;	
		}
		
		/*###################################################
		#		   			  INTERNAL						#
		#####################################################*/
		
		/**
		 * the hitter is resized after the current state
		 */
		protected function resizeHitter():void{
			if(_resizeHitterEnabled){
				hitArea.height = currState.height;
				hitArea.width  = currState.width;
				try{
					hitArea.y = currState.backGround.y;
					hitArea.x = currState.backGround.x;
				}catch(e:Error){
	//				Debug.trace("Button::resizeHitter : currState.backGround is missing - "+e, Debug.WARNING);
				}
			}
		}
			
		/**
		 * @param aState  the current state
		 * the former state is removed and the new state is added to the button as a child 
		 */
		protected function setState(aState:ButtonState):void{
			removeChild(currState.sprite);
			addChild(aState.sprite);
			currState = aState;
//			dispatchEvent(new ButtonEvent(currState.stateType,this));
			resizeHitter();
		} 
		
		/**
		 * called on each mouseEvent
		 * 
		 * @param event thrown MouseEvent
		 */
		protected function mouseEvent(event:MouseEvent):void {
			switch(event.type){
				case MouseEvent.MOUSE_OVER:						
					setState(overState);
					dispatchEvent(new ButtonEvent(OVER,this));
					break;
				case MouseEvent.MOUSE_DOWN:
					setState(downState);
					dispatchEvent(new ButtonEvent(DOWN,this));
					break;
				case MouseEvent.MOUSE_OUT:
					setState(upState);
					dispatchEvent(new ButtonEvent(OUT,this));
					break;
				case MouseEvent.MOUSE_UP:
					setState(upState);
					dispatchEvent(new ButtonEvent(UP,this));
					dispatchEvent(new ButtonEvent(CLICK,this));
					break;

			}
			if(sounds[event.type]!= undefined && sounds[event.type]!= null){
				audio.playSound(sounds[event.type]);
			}		
		}
		
		protected function inactiveMouseEvent(event:MouseEvent):void {
			dispatchEvent(new ButtonEvent(INACTIVE_CLICK,this));
		}
		
		/**
	 	* @param type:String  the state of the button that will be created
	 	*/
		protected function createState(type:String):ButtonState{
			var stateSprite:Sprite = getChildByName(type) as Sprite;
			if(stateSprite == null){
				return upState;
			}
			var state:ButtonState = new ButtonState(this,stateSprite,type,_id);	

			removeChild(state.sprite);
			addLocalizable(state);
			return state;	
		}
	}
}



